var express = require('express');
var router = express.Router();
const Business = require('../models/Business');
const Instance = require('../models/Instance');
const Category = require('../models/Category');
const SchemaIcon = require('../models/SchemaIcon');
const Relation = require('../models/Relation')
var formidable = require('formidable');
var fs = require('fs');
const mineType = require("mime-types");
var tools = require('../utils/tools')

/**
 * @swagger
 * /cmdb/businesses:
 *   get:
 *     tags:
 *       - 业务模型管理
 *     summary: 查询所有业务模型
 *     description: 查询所有业务模型
 *     responses:
 *       200:
 *         description: 不分页
 */
router.get('/', function (req, res, next) {
  Business.find((err, docs) => {
    if (err) return tools.handleError(res, err);
    return res.json({ status: 'success', data: docs })
  })
});

/**
 * @swagger
 * /cmdb/businesses/count:
 *   get:
 *     tags:
 *       - 业务模型管理
 *     summary: 业务模型数量
 *     description: 业务模型数量
 *     responses:
 *       200:
 *         description: 业务模型数量
 */
router.get('/count', async function (req, res, next) {
  var count = await Business.count()
  return res.json({ status: 'success', data: count })
});

/**
 * @swagger
 * /cmdb/businesses/{id}:
 *   get:
 *     tags:
 *       - 业务模型管理
 *     summary: 业务模型详情
 *     description: 业务模型详情
 *     parameters:
 *       - name: id
 *         description: ID或编码
 *         in: path
 *         required: true
 *         type: string
 *     responses:
 *       200:
 *         description: status/data结构
 */
router.get('/:id', function (req, res, next) {
  var isById = tools.isValidObjectId(req.params.id)
  var query = isById ? { _id: req.params.id } : { code: req.params.id }

  Business.findOne(query).populate('instances').exec((err, doc) => {
    if (err) return tools.handleError(res, err);
    return res.json({ status: 'success', data: doc })
  })
});

/**
 * @swagger
 * /cmdb/businesses:
 *   post:
 *     tags:
 *       - 业务模型管理
 *     summary: 创建业务模型
 *     description: 创建业务模型
 *     parameters:
 *       - name: code
 *         description: 模型编码
 *         in: formData
 *         required: true
 *         type: string
 *       - name: name
 *         description: 模型名称
 *         in: formData
 *         required: true
 *         type: string
 *       - name: desc
 *         description: 模型描述
 *         in: formData
 *         required: false
 *         type: string
 *       - name: instances
 *         description: 实例项
 *         in: formData
 *         required: false
 *         type: arrays
 *     responses:
 *       200:
 *         description: status/data结构
 */
router.post('/', async function (req, res, next) {
  const { code, name, desc, instances } = req.body

  var instanceRefs = []
  for (var i = 0; i < instances.length; i++) {
    var isById = tools.isValidObjectId(instances[i])
    var query = isById ? { _id: instances[i] } : { code: instances[i] }
    var inst = await Instance.findOne(query)
    if (inst) {
      instanceRefs.push(inst)
    }
  }

  Business.create({ code, name, desc, instances: instanceRefs }, function (err, doc) {
    if (err) {
      if (err.message.indexOf('duplicate key error') !== -1) {
        var msg = '唯一性约束错误'
        return res.json({ status: 'failure', data: msg })
      }
      return tools.handleError(res, err)
    };
    return res.json({ status: 'success', data: doc })
  })
})

/**
 * @swagger
 * /cmdb/businesses/{id}:
 *   put:
 *     tags:
 *       - 业务模型管理
 *     summary: 更新业务模型
 *     description: 更新业务模型
 *     parameters:
 *       - name: id
 *         description: ID或编码
 *         in: path
 *         required: true
 *         type: string
 *       - name: code
 *         description: 模型编码
 *         in: formData
 *         required: true
 *         type: string
 *       - name: name
 *         description: 模型名称
 *         in: formData
 *         required: true
 *         type: string
 *       - name: desc
 *         description: 模型描述
 *         in: formData
 *         required: false
 *         type: string
 *       - name: instances
 *         description: 实例ID或实例编码数组
 *         in: formData
 *         required: false
 *         type: arrays
 *     responses:
 *       200:
 *         description: status/data结构
 */
router.put('/:id', async function (req, res, next) {
  var isById = tools.isValidObjectId(req.params.id)
  var query = isById ? { _id: req.params.id } : { code: req.params.id }

  const { code, name, desc, instances } = req.body

  var instanceRefs = []
  for (var i = 0; i < instances.length; i++) {
    var isById = tools.isValidObjectId(instances[i])
    var instQuery = isById ? { _id: instances[i] } : { code: instances[i] }
    var inst = await Instance.findOne(instQuery)
    if (inst) {
      instanceRefs.push(inst)
    }
  }

  Business.findOneAndUpdate(query, { $set: { code, name, desc, instances: instanceRefs } }, { new: true }, function (err, doc) {
    if (err) {
      if (err.message.indexOf('duplicate key error') !== -1) {
        var msg = '唯一性约束错误'
        return res.json({ status: 'failure', data: msg })
      }
      return tools.handleError(res, err)
    };
    return res.json({ status: 'success', data: doc })
  })

})

/**
 * @swagger
 * /cmdb/businesses/{id}/topo:
 *   get:
 *     tags:
 *       - 业务模型管理
 *     summary: 业务模型拓扑
 *     description: 业务模型拓扑
 *     parameters:
 *       - name: id
 *         description: ID或编码
 *         in: path
 *         required: true
 *         type: string
 *       - name: noicon
 *         description: 是否返回icon
 *         in: query
 *         required: false
 *         type: number
 *     responses:
 *       200:
 *         description: status/data结构
 */
router.get('/:id/topo', async function (req, res, next) {
  var isById = tools.isValidObjectId(req.params.id)
  var query = isById ? { _id: req.params.id } : { code: req.params.id }
  var doc = await Business.findOne(query)
    .populate({ path: 'instances', populate: { path: 'relations' }, select: '-versions' })
    .populate({ path: 'instances', populate: { path: 'schemadef' } })

  if (!doc) {
    return tools.handleError(res, '业务模型不存在')
  }

  var noicon = req.query.noicon === 0 || req.query.noicon === '0'
  var nodes = []
  var edges = []

  for (var i = 0; i < doc.instances.length; i++) {
    var inst = doc.instances[i]
    let icon = await SchemaIcon.findOne({ schemadef: inst.schemadef })
    nodes.push({ id: inst.code, _id: inst._id, label: inst.name, category: inst.schemadef.category, icon: icon && !noicon ? icon.url : '' })
  }

  for (var i = 0; i < doc.instances.length; i++) {
    var inst = doc.instances[i]
    for (var j = 0; j < inst.relations.length; j++) {
      if (inst._id.toString() === inst.relations[j].src.toString() && doc.instances.some(it => it._id.toString() === inst.relations[j].dest.toString())) {
        var toInst = doc.instances.find(it => it._id.toString() === inst.relations[j].dest.toString())
        var relation = await Relation.findById(inst.relations[j].rela).populate(({ path: 'type' }))
        edges.push({ from: inst.code, to: toInst.code, arrows: 'from', font: { multi: true }, label: relation.type.srcdesc, attrs: inst.relations[j].attrs })
      }
    }
    var category = await Category.findOne({ code: inst.schemadef.category })
    var allAttrs = [...category.attrs, ...inst.schemadef.attrs]
    var foreigns = allAttrs.filter(attr => attr.dtype === 'foreign')
    for (var j = 0; j < foreigns.length; j++) {
      var attr = inst.attrs.find(it => it.key === foreigns[j].field && !!it.value)
      if (attr) {
        var foreignInst = await Instance.findOne({ code: attr.value }, { _id: 1, code: 1, name: 1, schemadef: 1 })
        if (doc.instances.some(it => it._id.toString() === foreignInst._id.toString())) {
          edges.push({ from: inst.code, to: foreignInst.code, arrows: 'to', font: { multi: true }, label: '' })
        }
      }
    }
  }

  return res.json({ status: 'success', data: { nodes, edges } })
});

/**
 * @swagger
 * /cmdb/businesses/{id}/instances:
 *   get:
 *     tags:
 *       - 业务模型管理
 *     summary: 业务模型下所有实例编码
 *     description: 业务模型下所有实例编码
 *     parameters:
 *       - name: id
 *         description: ID或编码
 *         in: path
 *         required: true
 *         type: string
 *     responses:
 *       200:
 *         description: status/data结构
 */
router.get('/:id/instances', function (req, res, next) {
  var isById = tools.isValidObjectId(req.params.id)
  var query = isById ? { _id: req.params.id } : { code: req.params.id }

  Business.findOne(query).populate({ path: 'instances', populate: { path: 'schemadef' }, select: '-versions' }).exec((err, doc) => {
    if (err) return tools.handleError(res, err);
    //var codeArray = doc.instances.map(it => it.code)

    return res.json({ status: 'success', data: doc.instances })
  })
});

/**
 * @swagger
 * /cmdb/businesses/{id}:
 *   delete:
 *     tags:
 *       - 业务模型管理
 *     summary: 删除业务模型
 *     description: 删除业务模型
 *     parameters:
 *       - name: id
 *         description: ID或编码
 *         in: path
 *         required: true
 *         type: string
 *     responses:
 *       200:
 *         description: status/data结构
 */
router.delete('/:id', async function (req, res, next) {
  var isById = tools.isValidObjectId(req.params.id)
  var query = isById ? { _id: req.params.id } : { code: req.params.id }

  Business.findOneAndDelete(query, function (err, doc) {
    if (err) return tools.handleError(res, err);
    return res.json({ status: 'success' })
  });
});

/**
 * @swagger
 * /cmdb/businesses/{id}/icon:
 *   post:
 *     tags:
 *       - 业务模型管理
 *     summary: 设置图标
 *     description: 设置图标
 *     parameters:
 *       - name: id
 *         description: ID或编码
 *         in: path
 *         required: true
 *         type: string
 *       - name: file
 *         description: 图片文件
 *         in: formData
 *         required: true
 *         type: file
 *     responses:
 *       200:
 *         description: status/data结构
 */
router.post('/:id/icon', async function (req, res, next) {
  var isById = tools.isValidObjectId(req.params.id)
  var query = isById ? { _id: req.params.id } : { code: req.params.id }

  var form = new formidable.IncomingForm();
  form.encoding = 'utf-8';
  form.keepExtensions = true;

  var doc = await Business.findOne(query)

  if (!doc) {
    return tools.handleError(res, '业务模型不存在')
  }

  form.parse(req, async (err, fields, files) => {
    if (err) return tools.handleError(res, err);
    const imgPath = files.file.path;
    const prefix = "data:" + mineType.lookup(imgPath) + ";base64,";
    const icon = fs.readFileSync(imgPath);
    const base64str = Buffer.from(icon, 'binary').toString('base64')

    doc.icon = prefix + base64str
    doc = await doc.save();

    return res.json({ status: 'success', data: doc })
  })
})

module.exports = router;
